import semver from 'semver'

describe('package-lock.json', () => {
  let packages = /** @type {import('./package-lock.json')["packages"]} */ ({})

  beforeAll(async () => {
    packages = (await import('./package-lock.json')).packages
  })

  describe('Dependabot updates', () => {
    /**
     * When this check fails, the incorrect `package-lock.json` can be repaired by:
     *
     * 1. checking out the Dependabot branch
     * 2. running `npm install` to remove the hoisted dependency
     *
     * {@link https://team-playbook.design-system.service.gov.uk/guides/version-control/pull-requests/#reviewing-a-pr-from-dependabot}
     */
    it("should not hoist 'optionalDependencies' to 'dependencies'", () => {
      // @ts-expect-error - Property 'dependencies' does not exist
      const { dependencies, optionalDependencies } = packages['']

      // List package names for comparison
      const packageNames = Object.keys(dependencies ?? {})
      const packageNamesOptional = Object.keys(optionalDependencies ?? {})

      // Check no optional dependencies are hoisted
      for (const name of packageNamesOptional) {
        expect(packageNames).not.toContain(name)
      }
    })
  })

  describe("Shared helper 'peerDependencies'", () => {
    it('should maintain `puppeteer` bundled `@puppeteer/browsers` compatibility', () => {
      const helpers = packages['shared/helpers']
      const puppeteer = packages['node_modules/puppeteer']

      // Bundled package `@puppeteer/browsers` versus peer dependencies
      const installed = puppeteer.dependencies['@puppeteer/browsers']
      const expected = helpers.peerDependencies['@puppeteer/browsers']

      expect({
        '@puppeteer/browsers': {
          parent: 'shared/helpers',
          installed,
          expected,
          compatible: semver.intersects(expected, installed)
        }
      }).toEqual({
        '@puppeteer/browsers': {
          parent: 'shared/helpers',
          installed,
          expected,
          compatible: true
        }
      })
    })

    /**
     * When this check fails, the incorrect `package-lock.json` can be repaired by:
     *
     * 1. checking out the Dependabot branch
     * 2. updating the version of `puppeteer-core` in the `peerDependencies` of
     *    `shared/helpers/package.json` so it is compatible with that of
     *    `puppeteer` in the other workspaces (usually the version that
     *    Dependabot will have bumped `puppeteer` to)
     * 3. running `npm install` to install the correct version of `puppeteer-core`
     *
     * {@link https://team-playbook.design-system.service.gov.uk/guides/version-control/pull-requests/#reviewing-a-pr-from-dependabot}
     */
    it('should have compatible versions of `puppeteer-core` and `puppeteer` across workspaces', () => {
      const helpers = packages['shared/helpers']

      for (const name of /** @type {const} */ ([
        'packages/govuk-frontend-review',
        'packages/govuk-frontend',
        'shared/helpers',
        'shared/tasks'
      ])) {
        // Development package `puppeteer` versus peer dependencies
        const installed = packages[name].devDependencies.puppeteer
        const expected = helpers.peerDependencies['puppeteer-core']

        expect({
          puppeteer: {
            parent: name,
            installed,
            expected,
            compatible: semver.intersects(expected, installed)
          }
        }).toEqual({
          puppeteer: {
            parent: name,
            installed,
            expected,
            compatible: true
          }
        })
      }
    })
  })
})
